package cn.iocoder.yudao.module.shop.service.giftcard;

import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import cn.iocoder.yudao.module.agent.convert.base.AgentConvert;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
import cn.iocoder.yudao.module.pay.framework.pay.core.WalletPayClient;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.wallet.PayWalletRechargeService;
import cn.iocoder.yudao.module.shop.controller.admin.giftcardrecord.vo.ShopGiftCardRecordCreateReqVO;
import cn.iocoder.yudao.module.shop.dal.dataobject.giftitem.ShopGiftItemDO;
import cn.iocoder.yudao.module.shop.dal.mysql.giftitem.ShopGiftItemMapper;
import cn.iocoder.yudao.module.shop.enums.GiftCardTypeEnum;
import cn.iocoder.yudao.module.shop.enums.ShopItemTimesEnum;
import cn.iocoder.yudao.module.shop.service.giftcardrecord.ShopGiftCardRecordService;
import cn.iocoder.yudao.module.shop.service.giftitem.ShopGiftItemService;
import cn.iocoder.yudao.module.shop.service.itemtimes.ShopItemTimesService;
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeSendReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeValidateReqDTO;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import com.google.common.collect.Maps;
import com.sun.corba.se.spi.ior.iiop.RequestPartitioningComponent;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import cn.iocoder.yudao.module.shop.controller.admin.giftcard.vo.*;
import cn.iocoder.yudao.module.shop.dal.dataobject.giftcard.ShopGiftCardDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;

import cn.iocoder.yudao.module.shop.convert.giftcard.ShopGiftCardConvert;
import cn.iocoder.yudao.module.shop.dal.mysql.giftcard.ShopGiftCardMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.module.shop.enums.ErrorCodeConstants.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;

/**
 * 礼品卡 Service 实现类
 *
 * @author 曹建伟
 */
@Service
@Validated
public class ShopGiftCardServiceImpl implements ShopGiftCardService {

    @Resource
    private ShopGiftCardMapper giftCardMapper;

    @Resource
    private ShopGiftItemMapper giftItemMapper;

    @Resource
    private ShopGiftItemService shopGiftItemService;

    @Resource
    private ShopGiftCardRecordService shopGiftCardRecordService;

    @Resource
    private MemberUserService memberUserService;

    @Resource
    private SmsCodeApi smsCodeApi;

    @Resource
    private ShopItemTimesService shopItemTimesService;

    @Resource
    private PayWalletRechargeService payWalletRechargeService;

    @Resource
    private PayOrderService payOrderService;

    @Override
    public Long createGiftCard(ShopGiftCardCreateReqVO createReqVO) {
        ShopGiftItemDO itemDO = giftItemMapper.selectOne(ShopGiftItemDO::getId, createReqVO.getGiftId());
        if(itemDO == null){
            throw exception(GIFT_ITEM_NOT_EXISTS);
        }
        // 插入
        ShopGiftCardDO giftCard = ShopGiftCardConvert.INSTANCE.convert(createReqVO);
        giftCard.setCardPwd("123");
        giftCardMapper.insert(giftCard);
        // 返回
        return giftCard.getId();
    }

    @Override
    public void updateGiftCard(ShopGiftCardUpdateReqVO updateReqVO) {
        // 校验存在
        validateGiftCardExists(updateReqVO.getId());
        // 更新
        ShopGiftCardDO updateObj = ShopGiftCardConvert.INSTANCE.convert(updateReqVO);
        giftCardMapper.updateById(updateObj);
    }

    @Override
    public void deleteGiftCard(Long id) {
        // 校验存在
        validateGiftCardExists(id);
        // 删除
        giftCardMapper.deleteById(id);
    }

    private void validateGiftCardExists(Long id) {
        if (giftCardMapper.selectById(id) == null) {
            throw exception(GIFT_CARD_NOT_EXISTS);
        }
    }

    @Override
    public ShopGiftCardDO getGiftCard(Long id) {
        return giftCardMapper.selectById(id);
    }

    @Override
    public ShopGiftCardDO getGiftCardByCardId(String id){
        return giftCardMapper.selectOne(ShopGiftCardDO::getCardId, id);
    }

    @Override
    public List<ShopGiftCardDO> getGiftCardList(Collection<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return ListUtil.empty();
        }
        return giftCardMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<ShopGiftCardDO> getGiftCardPage(ShopGiftCardPageReqVO pageReqVO) {
        return giftCardMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ShopGiftCardDO> getGiftCardList(ShopGiftCardExportReqVO exportReqVO) {
        return giftCardMapper.selectList(exportReqVO);
    }

    @Override
    public void activeCard(ShopGiftCardActiveReqVO reqVO){
        ShopGiftCardDO cardDO = null;

        if(reqVO.getCardId() != null){
            cardDO = giftCardMapper.selectOne(ShopGiftCardDO::getCardId, reqVO.getCardId());
        }else {
            cardDO = giftCardMapper.selectById(reqVO.getId());
        }

        if(cardDO == null){
            throw exception(GIFT_CARD_NOT_EXISTS);
        }

        if(cardDO.getActivated()){
            throw exception(GIFT_CARD_HAD_ACTIVATED);
        }

        cardDO.setSource(reqVO.getSource());
        cardDO.setActivated(true);

        giftCardMapper.updateById(cardDO);
    }

    @Override
    public void sendCard(ShopGiftCardSendReqVO reqVO){
        ShopGiftCardDO cardDO = null;
        cardDO = giftCardMapper.selectOne(ShopGiftCardDO::getCardId, reqVO.getCardId());

        if(cardDO != null){
            throw exception(GIFT_CARD_ID_EXISTS);
        }

        cardDO = new ShopGiftCardDO();
        cardDO.setCardId(reqVO.getCardId());
        cardDO.setSource(reqVO.getSource());
        cardDO.setTenantId(reqVO.getTenantId());
        cardDO.setBinded(false);
        cardDO.setActivated(true);
        cardDO.setGiftId(reqVO.getGiftId());
        cardDO.setCardPwd("123");

        giftCardMapper.insert(cardDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindCard(ShopGiftCardBindReqVO reqVO){
        if(reqVO.getId() == null){
            if(reqVO.getCode() == null){
                throw exception(GIFT_CARD_BIND_CODE);
            }

            SmsCodeValidateReqDTO smsCodeValidateReqDTO = new SmsCodeValidateReqDTO();
            smsCodeValidateReqDTO.setMobile(reqVO.getMobile());
            smsCodeValidateReqDTO.setScene(SmsSceneEnum.MEMBER_AGENT_BIND.getScene());
            smsCodeValidateReqDTO.setCode(reqVO.getCode());
            smsCodeApi.validateSmsCode(smsCodeValidateReqDTO);
        }

        ShopGiftCardDO cardDO = null;

        if(reqVO.getCardId() != null){
            cardDO = giftCardMapper.selectOne(ShopGiftCardDO::getCardId, reqVO.getCardId());
        }else {
            cardDO = giftCardMapper.selectById(reqVO.getId());
        }

        if(cardDO == null){
            throw exception(GIFT_CARD_NOT_EXISTS);
        }

        if(!cardDO.getActivated()){
            throw exception(GIFT_CARD_NOT_ACTIVATED);
        }

        if(cardDO.getBinded()){
            throw exception(GIFT_CARD_HAD_BINDED);
        }
//绑定只需要一个卡号就可以了
//        if(!cardDO.getCardPwd().equals(reqVO.getCardPwd())){
//            throw exception(GIFT_CARD_PWD_ERROR);
//        }

        if(reqVO.getId() == null){
            SmsCodeUseReqDTO smsCodeUseReqDTO = new SmsCodeUseReqDTO();
            smsCodeUseReqDTO.setMobile(reqVO.getMobile());
            smsCodeUseReqDTO.setScene(SmsSceneEnum.MEMBER_AGENT_BIND.getScene());
            smsCodeUseReqDTO.setCode(reqVO.getCode());
            smsCodeUseReqDTO.setUsedIp(getClientIP());
            smsCodeApi.useSmsCode(smsCodeUseReqDTO);
        }

        ShopGiftItemDO giftItemDO = shopGiftItemService.getGiftItem(cardDO.getGiftId());
        if(giftItemDO == null){
            throw exception(GIFT_ITEM_NOT_EXISTS);
        }

        // 次数绑定/物品绑定/金额充值
        if(giftItemDO.getType().equals(GiftCardTypeEnum.TIMES.getType())){
            bindTimes(reqVO.getMobile(), giftItemDO, cardDO);
        }else if(giftItemDO.getType().equals(GiftCardTypeEnum.GOODS.getType())){
            throw exception(GIFT_CARD_BIND_GOODS);
        }else if(giftItemDO.getType().equals(GiftCardTypeEnum.MONEY.getType())){
            bindMoney(reqVO.getMobile(), giftItemDO, cardDO);
        }

        cardDO.setMobile(reqVO.getMobile());
        cardDO.setBinded(true);

        giftCardMapper.updateById(cardDO);
    }

    @Override
    public void sendSmsCode(ShopGiftCardSmsCodeReqVO reqVO){
        SmsCodeSendReqDTO smsCodeSendReqDTO = AgentConvert.INSTANCE.convertSmsSendReqDTO(reqVO.getMobile(), SmsSceneEnum.MEMBER_AGENT_BIND.getScene(), getClientIP());
        smsCodeApi.sendSmsCode(smsCodeSendReqDTO);
    }

    private void bindTimes(String mobile, ShopGiftItemDO giftItemDO, ShopGiftCardDO cardDO){
        MemberUserDO memberUserDO = memberUserService.getUserByMobile(mobile);
        if(memberUserDO != null){
            throw exception(GIFT_CARD_BIND_ERROR);
        }

        memberUserDO = memberUserService.createUserIfAbsent(mobile, "127.0.0.1", TerminalEnum.WECHAT_WAP.getTerminal(), giftItemDO.getTenantId());
        shopItemTimesService.addTimes(memberUserDO.getId(), giftItemDO.getBizId(), giftItemDO.getNum(), ShopItemTimesEnum.ADD_GIFT.getName(), 0, giftItemDO.getTenantId());
        createRecord(giftItemDO.getTenantId(), memberUserDO.getId(), memberUserDO.getNickname(), mobile, giftItemDO.getName(), giftItemDO.getNum(), cardDO.getSource());
    }

    public ShopGiftCardStatisticsRespVO statisticsCount(Long id){
        ShopGiftCardStatisticsRespVO respVO = new ShopGiftCardStatisticsRespVO();
        respVO.setTotalCount(giftCardMapper.selectCount(ShopGiftCardDO::getGiftId, id));
        respVO.setActiveCount(giftCardMapper.selectCount(new LambdaQueryWrapperX<ShopGiftCardDO>()
                .eq(ShopGiftCardDO::getGiftId, id)
                .eq(ShopGiftCardDO::getActivated, true)));

        respVO.setUnactiveCount(respVO.getTotalCount() - respVO.getActiveCount());

        respVO.setBindedCount(giftCardMapper.selectCount(new LambdaQueryWrapperX<ShopGiftCardDO>()
                .eq(ShopGiftCardDO::getGiftId, id)
                .eq(ShopGiftCardDO::getBinded, true)));

        respVO.setUnbindedCount(giftCardMapper.selectCount(new LambdaQueryWrapperX<ShopGiftCardDO>()
                .eq(ShopGiftCardDO::getGiftId, id)
                .eq(ShopGiftCardDO::getBinded, false)));

        return  respVO;
    }

    private void bindMoney(String mobile, ShopGiftItemDO giftItemDO, ShopGiftCardDO cardDO){
        MemberUserDO memberUserDO = memberUserService.createUserIfAbsent(mobile, "127.0.0.1", TerminalEnum.WECHAT_WAP.getTerminal(), giftItemDO.getTenantId());

        // 创建订单 客户端发来单位是元
        PayWalletRechargeDO walletRecharge = payWalletRechargeService.createWalletRecharge(
                memberUserDO.getId(), UserTypeEnum.MEMBER.getValue(), "http://127.0.0.1", giftItemDO.getNum()*100, 0, null, "礼品卡金额充值");

        // 提交订单
        PayOrderSubmitReqVO submitReqVO = new PayOrderSubmitReqVO();
        submitReqVO.setChannelCode(PayChannelEnum.MOCK.getCode());
        submitReqVO.setDisplayMode(PayOrderDisplayModeEnum.NONE.getMode());
        submitReqVO.setReturnUrl("http://127.0.0.1");
        submitReqVO.setId(walletRecharge.getPayOrderId());
        Map<String, String> channelExtras = Maps.newHashMapWithExpectedSize(2);
        channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(memberUserDO.getId()));
        channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(UserTypeEnum.MEMBER.getValue()));
        submitReqVO.setChannelExtras(channelExtras);
        payOrderService.submitOrder(submitReqVO, "http://127.0.0.1");

        createRecord(giftItemDO.getTenantId(), memberUserDO.getId(), memberUserDO.getNickname(), mobile, giftItemDO.getName(), giftItemDO.getNum(), cardDO.getSource());
    }

    private void createRecord(Long tenantId, Long memberId, String nickname, String mobile, String name, Integer num, String source){
        ShopGiftCardRecordCreateReqVO reqVO = new ShopGiftCardRecordCreateReqVO();
        reqVO.setMemberId(memberId);
        reqVO.setNickname(nickname);
        reqVO.setMobile(mobile);
        reqVO.setNum(num);
        reqVO.setSource(source);
        reqVO.setName(name);
        reqVO.setTenantId(tenantId);

        shopGiftCardRecordService.createGiftCardRecord(reqVO);
    }

}
